home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / Extras / MIDI / camd-37.1 / development / devs / midi / internal.asm < prev    next >
Encoding:
Assembly Source File  |  1994-02-15  |  15.2 KB  |  750 lines

  1. ************************************************************************
  2. *                 C. A. M. D.                   *
  3. ************************************************************************
  4. * CMU Amiga Midi Driver - Carnegie Mellon University               *
  5. * 1988            - Commodore Amiga                   *
  6. *                                       *
  7. * Design & Development    - Roger B. Dannenberg                   *
  8. *            - Jean-Christophe Dhellemmes               *
  9. *            - Bill Barton                       *
  10. * Copyright 1989 Carnegie Mellon University                   *
  11. ************************************************************************
  12. *
  13. * internal.asm - Example CAMD MIDI Device Driver for internal serial
  14. *         port.
  15. *
  16. * This is merely an example.  The internal serial port is normally
  17. * managed by camd.library.
  18. *
  19. ************************************************************************
  20. * Date          | Change
  21. *-----------------------------------------------------------------------
  22. * 06-Jan-1990 : Created (BB)
  23. ************************************************************************
  24.  
  25.       nolist
  26.     include "exec/types.i"
  27.     include "exec/execbase.i"           ; for FlushDevice()
  28.     include "exec/macros.i"
  29.     include "hardware/cia.i"
  30.     include "hardware/custom.i"
  31.     include "hardware/intbits.i"
  32.     include "midi/devices.i"
  33.     include "resources/misc.i"
  34.       list
  35.  
  36.  
  37. Version  equ 0
  38. Revision equ 0
  39. Ports     equ 1
  40.  
  41.  
  42.     section driver,data
  43.  
  44.         ; external
  45.     xref    _AbsExecBase
  46.     xref    _custom
  47.     xref    _ciab
  48.  
  49.  
  50.     section driver,code
  51.  
  52.  
  53. ****************************************************************
  54. *
  55. *   Standard MIDI Device driver header
  56. *
  57. ****************************************************************
  58.  
  59. ; code at start of file in case anyone tries to execute us as a program
  60.  
  61.     entry    FalseStart
  62. FalseStart
  63.     moveq    #-1,d0
  64.     rts
  65.  
  66. MDD ; struct MidiDeviceData
  67.     dc.l    MDD_Magic    ; mdd_Magic
  68.     dc.l    Name        ; mdd_Name
  69.     dc.l    IDString    ; mdd_IDString
  70.     dc.w    Version     ; mdd_Version
  71.     dc.w    Revision    ; mdd_Revision
  72.     dc.l    Init        ; mdd_Init
  73.     dc.l    Expunge     ; mdd_Expunge
  74.     dc.l    OpenPort    ; mdd_OpenPort
  75.     dc.l    ClosePort    ; mdd_ClosePort
  76.     dc.b    Ports        ; mdd_NPorts
  77.     dc.b    0        ; mdd_Flags
  78.  
  79. Name        dc.b    'Internal',0
  80. IDString    dc.b    'Internal serial port MIDI device driver',0
  81.         ds.w    0    ; force word alignment
  82.  
  83.  
  84. ****************************************************************
  85. *
  86. *   Serial Port Stuff
  87. *
  88. ****************************************************************
  89.  
  90. SerFreq_NTSC equ    3579545
  91. SerFreq_PAL equ     3546895
  92.  
  93. MIDIBPS     equ     31250
  94.  
  95. SetSerPer   macro   ; freq
  96.     move.w    #(\1+MIDIBPS/2)/MIDIBPS-1,SerPer    ; bits 0-14: period.  bit 15: 9/8 bit selection
  97.     endm
  98.  
  99.  
  100. INTF_CLR    equ 0
  101.     BITDEF    INT,SET,INTB_SETCLR
  102.  
  103.         ; serdatr register bit def's (not found in any include file)
  104.  
  105.     BITDEF    SERDAT,OVRUN,15
  106.     BITDEF    SERDAT,RBF,14
  107.     BITDEF    SERDAT,TBE,13
  108.     BITDEF    SERDAT,TSRE,12
  109.  
  110.     STRUCTURE SerInt,IS_SIZE
  111.     UWORD    si_pad0
  112.     APTR    si_OldInt
  113.     APTR    si_Data
  114.     APTR    si_Code
  115.     LABEL    SerInt_Size
  116.  
  117.  
  118.     section driver,data        ; data
  119.  
  120. MiscBase    ds.l    1            ; misc.resource pointer
  121. SerPer        ds.w    1            ; serper value
  122. OldIntEna   ds.w    1            ; original value of TBE and RBF bits
  123.  
  124. MPD0 ; struct MidiPortData
  125.         dc.l    ActivateXmit
  126.  
  127. SerXmitInt
  128.         dc.l    0            ; ln_Succ
  129.         dc.l    0            ; ln_Pred
  130.         dc.b    NT_INTERRUPT    ; ln_Type
  131.         dc.b    0            ; ln_Pri
  132.         dc.l    Name        ; ln_Name
  133.         dc.l    SerXmitInt+si_Data ; is_Data
  134.         dc.l    XmitHandler     ; is_Code
  135.         dc.w    0            ; si_pad0
  136.         dc.l    0            ; si_OldInt
  137.         dc.l    0            ; si_Data
  138.         dc.l    0            ; si_Code
  139.  
  140. SerRecvInt
  141.         dc.l    0            ; ln_Succ
  142.         dc.l    0            ; ln_Pred
  143.         dc.b    NT_INTERRUPT    ; ln_Type
  144.         dc.b    0            ; ln_Pri
  145.         dc.l    Name        ; ln_Name
  146.         dc.l    SerRecvInt+si_Data ; is_Data
  147.         dc.l    RecvHandler     ; is_Code
  148.         dc.w    0            ; si_pad0
  149.         dc.l    0            ; si_OldInt
  150.         dc.l    0            ; si_Data
  151.         dc.l    0            ; si_Code
  152.  
  153.     section driver,code
  154.  
  155. ****************************************************************
  156. *
  157. *   MidiDeviceData Functions
  158. *
  159. ****************************************************************
  160.  
  161. ****************************************************************
  162. *
  163. *   Init
  164. *
  165. *   FUNCTION
  166. *    Gets called by CAMD after being LoadSeg'ed.
  167. *
  168. *   INPUTS
  169. *    None
  170. *
  171. *   RESULTS
  172. *    TRUE if successful, FALSE on failure.
  173. *
  174. ****************************************************************
  175.  
  176. init_reg reg a6
  177.  
  178. Init
  179.     movem.l init_reg,-(sp)
  180.  
  181.     move.l    _AbsExecBase,a6         ; A6 = SysBase
  182.  
  183.         ; get misc.resource pointer
  184.     lea    MiscName,a1            ; open misc.resource
  185.     JSRLIB    OpenResource
  186.     move.l    d0,MiscBase
  187.     beq    init_ret
  188.  
  189.         ; calculate SerPer
  190.     cmp.b    #50,VBlankFrequency(a6)     ; is PAL?
  191.     beq    init_pal
  192.     SetSerPer SerFreq_NTSC            ; set our local SerPer variable (not custom.serper)
  193.     bra    init_serperdone
  194. init_pal
  195.     SetSerPer SerFreq_PAL            ; set out local SerPer variable
  196. init_serperdone
  197.  
  198.     moveq    #1,d0                ; return TRUE
  199. init_ret
  200.     movem.l (sp)+,init_reg
  201.     rts
  202.  
  203.  
  204. ****************************************************************
  205. *
  206. *   Expunge
  207. *
  208. *   FUNCTION
  209. *    Gets called by CAMD immediately before being
  210. *    UnLoadSeg'ed.
  211. *
  212. *   INPUTS
  213. *    None
  214. *
  215. *   RESULTS
  216. *    None
  217. *
  218. ****************************************************************
  219.  
  220. Expunge
  221.     rts
  222.  
  223.  
  224. ****************************************************************
  225. *
  226. *   OpenPort
  227. *
  228. *   FUNCTION
  229. *    Open a MIDI port.
  230. *
  231. *   INPUTS
  232. *    D0.b - Port number (should always be 0 for this driver)
  233. *    A0 - Xmit function
  234. *    A1 - Recv function
  235. *    A2 - Data
  236. *
  237. *   RESULT
  238. *    D0 - pointer to MidiPortData structure.
  239. *
  240. ****************************************************************
  241.  
  242. op_reg    reg a6
  243.  
  244. OpenPort
  245.     movem.l op_reg,-(sp)
  246.  
  247.     move.l    _AbsExecBase,a6         ; A6 = SysBase
  248.  
  249.     movem.l a0/a1,-(sp)                 ; save a0/a1
  250.     bsr    AllocSerial
  251.     movem.l (sp)+,a0/a1
  252.     ext.l    d0
  253.     beq    op_ret
  254.  
  255.             ; set SerXmitInt
  256.     move.l    a0,SerXmitInt+si_Code
  257.     move.l    a2,SerXmitInt+si_Data
  258.  
  259.             ; set SerRecvInt
  260.     move.l    a1,SerRecvInt+si_Code
  261.     move.l    a2,SerRecvInt+si_Data
  262.  
  263.     lea    _custom,a0            ; A0 = custom
  264.     move.w    #INTF_TBE!INTF_RBF,d1        ; D1 = RBF | TBE mask and int disable
  265.  
  266.             ; save original TBE and RBF intena settings
  267.     move.w    intenar(a0),d0
  268.     and.w    d1,d0                ; mask with RBF|TBE mask
  269.     move.w    d0,OldIntEna
  270.  
  271.     move.w    d1,intena(a0)               ; disable TBE and RBF interrupts
  272.     move.w    d1,intreq(a0)               ; clear pending TBE and RBF interrupts
  273.     move.w    SerPer,serper(a0)           ; set serper
  274.  
  275.             ; set TBE interrupt vector
  276.     moveq    #INTB_TBE,d0
  277.     lea    SerXmitInt,a1
  278.     JSRLIB    SetIntVector
  279.     move.l    d0,SerXmitInt+si_OldInt     ; save old vector
  280.  
  281.             ; set RBF interrupt vector
  282.     moveq    #INTB_RBF,d0
  283.     lea    SerRecvInt,a1
  284.     JSRLIB    SetIntVector
  285.     move.l    d0,SerRecvInt+si_OldInt     ; save old vector
  286.  
  287.     move.w    #INTF_SET!INTF_RBF,_custom+intena   ; enable RBF
  288.     move.w    #INTF_SET!INTF_TBE,_custom+intreq   ; set a pending TBE
  289.     bclr.b    #CIAB_COMDTR,_ciab+ciapra   ; turn on DTR bit (active low)
  290.  
  291.     lea    MPD0,a0
  292.     move.l    a0,d0                ; return pointer to MidiPortData
  293.  
  294. op_ret
  295.     movem.l (sp)+,op_reg
  296.     rts
  297.  
  298.  
  299.  
  300. ****************************************************************
  301. *
  302. *   ClosePort
  303. *
  304. *   FUNCTION
  305. *    Close a MIDI port.
  306. *
  307. *   INPUTS
  308. *    D0.b - Port number (always 0 for this driver).
  309. *
  310. *   RESULT
  311. *    None
  312. *
  313. ****************************************************************
  314.  
  315. cp_reg    reg a6
  316.  
  317. ClosePort
  318.     movem.l cp_reg,-(sp)
  319.  
  320.     move.l    _AbsExecBase,a6         ; A6 = SysBase
  321.  
  322.     bsr    WaitSerial
  323.  
  324.     bset.b    #CIAB_COMDTR,_ciab+ciapra        ; turn off DTR bit (active low)
  325.     move.w    #INTF_CLR!INTF_TBE!INTF_RBF,_custom+intena  ; disable RBF & TBE
  326.     move.w    #INTF_CLR!INTF_TBE!INTF_RBF,_custom+intreq  ; clear pending RBF & TBE requests
  327.  
  328.             ; restore original TBE interrupt vector
  329.     moveq    #INTB_TBE,d0
  330.     move.l    SerXmitInt+si_OldInt,a1
  331.     JSRLIB    SetIntVector
  332.  
  333.             ; restore original RBF interrupt vector
  334.     moveq    #INTB_RBF,d0
  335.     move.l    SerRecvInt+si_OldInt,a1
  336.     JSRLIB    SetIntVector
  337.  
  338.     move.w    OldIntEna,d0
  339.     beq    cp_nointena
  340.     or.w    #INTF_SET,d0
  341.     move.w    d0,_custom+intena
  342. cp_nointena
  343.  
  344.     bsr    FreeSerial
  345.  
  346.     movem.l (sp)+,cp_reg
  347.     rts
  348.  
  349.  
  350. ****************************************************************
  351. *
  352. *   ActivateXmit
  353. *
  354. *   FUNCTION
  355. *    Activate the transmit interrupt.  There is normally
  356. *    one of these functions for every port in order to
  357. *    reduce table lookup time.
  358. *
  359. *   INPUTS
  360. *    A2 - Data passed to OpenPort() (not used here)
  361. *
  362. *   RESULT
  363. *    None
  364. *
  365. ****************************************************************
  366.  
  367. ActivateXmit
  368.     move.w    #INTF_SET!INTF_TBE,_custom+intena   ; enable TBE interrupt, but leave request pending
  369.     rts
  370.  
  371.  
  372. ****************************************************************
  373. *
  374. *   WaitSerial
  375. *
  376. *   FUNCTION
  377. *    Wait until Amiga serial port TSRE bit is set.  This
  378. *    indicates that the serial shift register is empty.
  379. *
  380. *   INPUTS
  381. *    None
  382. *
  383. *   RESULTS
  384. *    None
  385. *
  386. *   NOTE
  387. *    This function busy waits!!!  It should only be called
  388. *    once the transmit queue has emptied (i.e. TBE has
  389. *    already been set) such that no more than 320us is
  390. *    wasted here.
  391. *
  392. ****************************************************************
  393.  
  394. ws_reg reg
  395.  
  396. WaitSerial
  397.     movem.l ws_reg,-(sp)
  398.  
  399. ws_loop
  400.     move.w    _custom+serdatr,d0
  401.     btst.l    #SERDATB_TSRE,d0
  402.     beq    ws_loop
  403.  
  404.     movem.l (sp)+,ws_reg
  405.     rts
  406.  
  407.  
  408.  
  409. ****************************************************************
  410. *
  411. *   Serial Interrupt Handlers
  412. *
  413. ****************************************************************
  414.  
  415.  
  416. ****************************************************************
  417. *
  418. *   XmitHandler
  419. *
  420. *   FUNCTION
  421. *    Amiga serial port transmit interrupt handler.  Calls
  422. *    the general transmit handler and expects a byte in
  423. *    D0 and a last byte flag in D1.
  424. *
  425. *    When the last byte is detected, the TBE interrupt
  426. *    is disabled, thus deferring calling XmitHandler
  427. *    again until there are some bytes ready to send.
  428. *    CAMD calls ActivateXmit when there are more bytes
  429. *    to send.
  430. *
  431. *   INPUTS
  432. *    A0 - custom
  433. *    A1 - Data
  434. *    A6 - SysBase
  435. *
  436. *   RESULTS
  437. *    None
  438. *
  439. *   NOTE
  440. *    A5 is scratch.
  441. *
  442. ****************************************************************
  443.  
  444. sxh_reg reg a2
  445.  
  446. XmitHandler
  447.     movem.l sxh_reg,-(sp)
  448.  
  449.     movem.l (a1),a2/a5                  ; A2 = Data, A5 = XmitHandler
  450.  
  451. sxh_loop
  452.     move.w    #INTF_CLR!INTF_TBE,_custom+intreq   ; clear TBE interrupt request
  453.  
  454.     jsr    (a5)                        ; returns byte in D0, last byte flag in D1
  455.  
  456.     or.w    #$100,d0            ; add stop bit
  457.     move.w    d0,_custom+serdat        ; send byte
  458.  
  459.     tst.b    d1                ; is last byte?
  460.     beq    sxh_notlast
  461.                         ; xmit queue is empty
  462.     move.w    #INTF_CLR!INTF_TBE,_custom+intena   ; disable TBE interrupt.
  463.     bra    sxh_done            ; next request remains pending until there are more bytes to send
  464.  
  465. sxh_notlast                    ; test for another TBE
  466.     btst.b    #INTB_TBE&7,_custom+intreqr+(15-INTB_TBE)/8
  467.     bne    sxh_loop
  468.  
  469. sxh_done
  470.     movem.l (sp)+,sxh_reg
  471.     rts
  472.  
  473.  
  474.  
  475.     if 0
  476.  
  477. ****************************************************************
  478. *
  479. *   XmitHandler
  480. *
  481. *   FUNCTION
  482. *    Amiga serial port transmit interrupt handler.  Called
  483. *    by TBE interrupt vector.  Calls the CAMD transmit
  484. *    handler and expects one of the following return values
  485. *    in d0.w:
  486. *
  487. *        $00mm - a MIDI byte in the lower byte to transmit.
  488. *        $ffff - if no byte to send (queue was empty).
  489. *
  490. *   INPUTS
  491. *    A0 - custom
  492. *    A1 - pointer to SerInt.Data
  493. *    A6 - SysBase
  494. *
  495. *   RESULTS
  496. *    None
  497. *
  498. *   NOTE
  499. *    A5 is scratch.
  500. *
  501. ****************************************************************
  502.  
  503. sxh_reg reg a2
  504.  
  505. XmitHandler
  506.     movem.l sxh_reg,-(sp)
  507.  
  508.     movem.l (a1),a2/a5
  509.  
  510. sxh_loop
  511.     move.w    #INTF_TBE,intreq(a0)    ; clear the interrupt request
  512.  
  513.     jsr    (a5)
  514.  
  515.     or.w    #$100,d0        ; add stop bit
  516.     bmi    sxh_skip        ; if negative, there's no byte to send
  517.  
  518.     lea    _custom,a0        ; see if TBE is still set
  519.     move.w    d0,serdat(a0)           ; send byte
  520.     move.w    intreqr(a0),d0          ; (don't know if btst.b is safe on custom chips)
  521.     and.w    #INTF_TBE,d0            ;    ^^^ JOE: It's not!!
  522.     bne    sxh_loop
  523.  
  524. sxh_skip
  525.     movem.l (sp)+,sxh_reg
  526.     rts
  527.  
  528.     endc
  529.  
  530.  
  531. ****************************************************************
  532. *
  533. *   RecvHandler
  534. *
  535. *   FUNCTION
  536. *    Amiga serial port receive interrupt handler.  Called
  537. *    by RBF interrupt vector.  Calls the CAMD receive
  538. *    handler with received data until there are no more bytes
  539. *    pending in the serial receive hardware.
  540. *
  541. *   INPUTS
  542. *    A0 - custom
  543. *    A1 - pointer to SerInt.Data
  544. *    A6 - SysBase
  545. *
  546. *   RESULTS
  547. *    None
  548. *
  549. *   NOTE
  550. *    A5 is scratch.
  551. *
  552. ****************************************************************
  553.  
  554. srh_reg reg a2
  555.  
  556. RecvHandler
  557.     movem.l srh_reg,-(sp)
  558.  
  559.     movem.l (a1),a2/a5
  560.     move.w    serdatr(a0),d0
  561.  
  562. srh_loop
  563.     move.w    #INTF_CLR!INTF_RBF,intreq(a0)   ; clear the interrupt request
  564.  
  565.     jsr    (a5)
  566.  
  567.     lea    _custom,a0        ; see if RBF is still set
  568.     move.w    serdatr(a0),d0
  569.     btst.l    #SERDATB_RBF,d0
  570.     bne    srh_loop
  571.  
  572.     movem.l (sp)+,srh_reg
  573.     rts
  574.  
  575.  
  576.  
  577. ****************************************************************
  578. *
  579. *   misc.resource serial stuff
  580. *
  581. ****************************************************************
  582.  
  583. ****************************************************************
  584. *
  585. *   AllocSerial
  586. *
  587. *   FUNCTION
  588. *    Allocate misc.resource channels for the serial port.
  589. *    Call FlushDevice("serial.device") on failure and try
  590. *    again.
  591. *
  592. *   INPUTS
  593. *    A6 - SysBase
  594. *
  595. *   RESULT
  596. *    D0.w - TRUE on success.
  597. *
  598. ****************************************************************
  599.  
  600. as_reg    reg
  601.  
  602. AllocSerial
  603.     movem.l as_reg,-(sp)
  604.  
  605.     JSRLIB    Forbid                ; remain atomic
  606.  
  607.     bsr    AttemptSerMisc            ; attempt to get serial misc.resource channels
  608.     tst.w    d0
  609.     bne    as_done             ; if OK, return
  610.  
  611.     lea    SerialName,a1            ; otherwise, FlushDevice("serial.device")
  612.     bsr    FlushDevice
  613.     bsr    AttemptSerMisc            ; and try the serial misc.resource stuff again
  614.  
  615. as_done
  616.     move.w    d0,-(sp)
  617.     JSRLIB    Permit
  618.     move.w    (sp)+,d0
  619.  
  620.     movem.l (sp)+,as_reg
  621.     rts
  622.  
  623.  
  624. ****************************************************************
  625. *
  626. *   AttemptSerMisc
  627. *
  628. *   FUNCTION
  629. *    Attempt to allocate misc.resource channels for the
  630. *    serial port.
  631. *
  632. *   INPUTS
  633. *    None
  634. *
  635. *   RESULT
  636. *    D0.w - TRUE on success.
  637. *
  638. ****************************************************************
  639.  
  640. asm_reg reg a6
  641.  
  642. AttemptSerMisc
  643.     movem.l asm_reg,-(sp)
  644.  
  645.     move.l    MiscBase,a6            ; A6 = MiscBase
  646.  
  647.     moveq    #MR_SERIALBITS,d0        ; alloc SERIALBITS
  648.     lea    Name,a1
  649.     JSRLIB    AllocMiscResource
  650.     tst.l    d0                ; if return is non-zero, it's in use
  651.     bne    asm_fail
  652.  
  653.     moveq    #MR_SERIALPORT,d0        ; alloc SERIALPORT
  654.     lea    Name,a1
  655.     JSRLIB    AllocMiscResource
  656.     tst.l    d0                ; if return is zero, we got it
  657.     beq    asm_ok
  658.  
  659.     moveq    #MR_SERIALBITS,d0        ; free SERIALBITS on SERIALPORT failure
  660.     JSRLIB    FreeMiscResource
  661.  
  662. asm_fail
  663.     moveq    #0,d0
  664.     bra    asm_ret
  665.  
  666. asm_ok
  667.     moveq    #1,d0
  668.  
  669. asm_ret
  670.     movem.l (sp)+,asm_reg
  671.     rts
  672.  
  673.  
  674.  
  675. ****************************************************************
  676. *
  677. *   FreeSerial
  678. *
  679. *   FUNCTION
  680. *    Free misc.resource channels for the serial port.
  681. *
  682. *   INPUTS
  683. *    None
  684. *
  685. *   RESULT
  686. *    None
  687. *
  688. ****************************************************************
  689.  
  690. fs_reg    reg a6
  691.  
  692. FreeSerial
  693.     movem.l fs_reg,-(sp)
  694.  
  695.     move.l    MiscBase,a6            ; A6 = MiscBase
  696.  
  697.     moveq    #MR_SERIALBITS,d0        ; free SERIALBITS
  698.     JSRLIB    FreeMiscResource
  699.  
  700.     moveq    #MR_SERIALPORT,d0        ; free SERIALPORT
  701.     JSRLIB    FreeMiscResource
  702.  
  703.     movem.l (sp)+,fs_reg
  704.     rts
  705.  
  706.  
  707.  
  708. ****************************************************************
  709. *
  710. *   FlushDevice
  711. *
  712. *   FUNCTION
  713. *    Force expunge of a Device.
  714. *
  715. *   INPUTS
  716. *    A1 - Name of device.
  717. *    A6 - SysBase
  718. *
  719. *   RESULT
  720. *    None
  721. *
  722. *   NOTE
  723. *    Assumes caller has surrounded this call with
  724. *    Forbid/Permit
  725. *
  726. ****************************************************************
  727.  
  728. fd_reg    reg
  729.  
  730. FlushDevice
  731.     movem.l fd_reg,-(sp)
  732.  
  733.     lea    DeviceList(a6),a0
  734.     JSRLIB    FindName
  735.     tst.l    d0                ; if not in the device list, skip
  736.     beq    fd_ret
  737.  
  738.     move.l    d0,a1                ; otherwise force expunge
  739.     JSRLIB    RemDevice
  740.  
  741. fd_ret
  742.     movem.l (sp)+,fd_reg
  743.     rts
  744.  
  745.  
  746. MiscName MISCNAME
  747. SerialName dc.b 'serial.device',0
  748.  
  749.     end
  750.